/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package filesecurity;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author lehoangkhanh
 */
public class Utils {
    public static byte[] readFile(String filepath){
        File file  = new File(filepath);
        ByteArrayOutputStream ous = null;
        InputStream ios = null;
        try {
            byte[] buffer = new byte[4096];
            ous = new ByteArrayOutputStream();
            ios = new FileInputStream(file);
            int read = 0;
            while ((read = ios.read(buffer)) != -1)
                ous.write(buffer, 0, read);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (ous != null)
                    ous.close();
            } catch (IOException e) {
            }
            try {
                if (ios != null)
                    ios.close();
            } catch (IOException e) {}
        }
        return ous.toByteArray();
    }
    public static void writeFile(byte[] data, String filepath){
        BufferedOutputStream bs = null;
        try {

            FileOutputStream fs = new FileOutputStream(new File(filepath));
            bs = new BufferedOutputStream(fs);
            bs.write(data);
            bs.close();
            bs = null;

        } catch (Exception e) {
            e.printStackTrace();
        }
        if (bs != null) try { bs.close(); } catch (Exception e) {}
    }
    public static byte[] getHeader(byte[] data){
        byte[] tmp = null;
        byte[] algoByte = new byte[4];
        byte[] encryptedKeyLengthByte = new byte[4];
        int t=0;
        for(int i=0; i< 4; i++){
            algoByte[i] = data[t];
            t++;
        }
        for(int i=0; i<4; i++){
            encryptedKeyLengthByte[i] = data[t]; 
            t++;
        }
        int algo = algoByte[0] << 24 | (algoByte[1] & 0xFF) << 16 | (algoByte[2] & 0xFF) << 8 | (algoByte[3] & 0xFF);
        int encryptedKeyLength = encryptedKeyLengthByte[0] << 24 | (encryptedKeyLengthByte[1] & 0xFF) << 16 | (encryptedKeyLengthByte[2] & 0xFF) << 8 | (encryptedKeyLengthByte[3] & 0xFF);
        if(Crypto.getAlgo(algo)=="AES"){
            int headerLength = 4 + 4 + encryptedKeyLength + 16;
            tmp = new byte[headerLength];
            for(int i=0; i<headerLength; i++){
                tmp[i] = data[i];
            }
            return tmp;
        }
        if(Crypto.getAlgo(algo)=="DES"){
            int headerLength = 4 + 4 + encryptedKeyLength + 8;
            tmp = new byte[headerLength];
            for(int i=0; i<headerLength; i++){
                tmp[i] = data[i];
            }
            return tmp;
        }
        return null;
    }
    public static byte[] getEncryptedKey(byte[] header){
        byte[] encryptedKeyLengthByte = new byte[4];
        int begin=4;
        for(int i=0; i<4; i++){
            encryptedKeyLengthByte[i] = header[begin];
            begin++;
        }
        int encryptedKeyLength = encryptedKeyLengthByte[0] << 24 | (encryptedKeyLengthByte[1] & 0xFF) << 16 | (encryptedKeyLengthByte[2] & 0xFF) << 8 | (encryptedKeyLengthByte[3] & 0xFF);
        byte[] encryptedKey = new byte[encryptedKeyLength];
        int t = 8;
        for(int i=0; i<encryptedKeyLength; i++){
            encryptedKey[i] = header[t];
            t++;
        }
        return encryptedKey;
    }
    public static int getAlgo(byte[] header){
        byte[] algoByte = new byte[4];
        for(int i=0; i<4; i++){
            algoByte[i] = header[i];
        }
        int algo = algoByte[0] << 24 | (algoByte[1] & 0xFF) << 16 | (algoByte[2] & 0xFF) << 8 | (algoByte[3] & 0xFF);
        return algo;
    }
    public static byte[] getIV(byte[] header){
        byte[] algoByte = new byte[4];
        byte[] encryptedKeyLengthByte = new byte[4];
        int t=0;
        for(int i=0; i< 4; i++){
            algoByte[i] = header[t];
            t++;
        }
        for(int i=0; i<4; i++){
            encryptedKeyLengthByte[i] = header[t]; 
            t++;
        }
        int algo = algoByte[0] << 24 | (algoByte[1] & 0xFF) << 16 | (algoByte[2] & 0xFF) << 8 | (algoByte[3] & 0xFF);
        int encryptedKeyLength = encryptedKeyLengthByte[0] << 24 | (encryptedKeyLengthByte[1] & 0xFF) << 16 | (encryptedKeyLengthByte[2] & 0xFF) << 8 | (encryptedKeyLengthByte[3] & 0xFF);
        if(Crypto.getAlgo(algo)=="AES"){
            int begin = 4 + 4 + encryptedKeyLength;
            byte[] iv = new byte[16];
            for(int i=0; i<16; i++){
                iv[i] = header[begin];
                begin++;
            }
            return iv;
        }
        if(Crypto.getAlgo(algo)=="DES"){
            int begin = 4 + 4 + encryptedKeyLength;
            byte[] iv = new byte[8];
            for(int i=0; i<8; i++){
                iv[i] = header[begin];
                begin++;
            }
            return iv;
        }
        return null;
    }
    public static byte[] addHeader(byte[] data, int algo, int encryptedKeyLength, byte[] encryptedKey, byte[] iv ){
        
        byte[] tmp = new byte[4 + 4 + encryptedKey.length + iv.length + data.length];
        byte[] algoByte = new byte[] {(byte)(algo >> 24), (byte)(algo >> 16), (byte)(algo >> 8), (byte)algo};
        byte[] encryptedKeyLengthByte = new byte[] {(byte)(encryptedKeyLength >> 24), (byte)(encryptedKeyLength >> 16), (byte)(encryptedKeyLength >> 8), (byte)encryptedKeyLength};
        
        int t=0;
        for(int i=0; i<4; i++){
            tmp[t] = algoByte[i];
            t++;
        }
        for(int i=0; i<4; i++){
            tmp[t] = encryptedKeyLengthByte[i];
            t++;
        }
        for(int i=0; i<encryptedKey.length; i++){
            tmp[t] = encryptedKey[i];
            t++;
        }
        for(int i=0; i<iv.length; i++){
            tmp[t] = iv[i];
            t++;
        }
        for(int i=0; i<data.length; i++){
            tmp[t] = data[i];
            t++;
        }
        return tmp;
    }
    public static byte[] removeHeader(byte[] data){
        byte[] algoByte = new byte[4];
        byte[] encryptedKeyLengthByte = new byte[4];
        int t=0;
        for(int i=0; i< 4; i++){
            algoByte[i] = data[t];
            t++;
        }
        for(int i=0; i<4; i++){
            encryptedKeyLengthByte[i] = data[t]; 
            t++;
        }
        int algo = algoByte[0] << 24 | (algoByte[1] & 0xFF) << 16 | (algoByte[2] & 0xFF) << 8 | (algoByte[3] & 0xFF);
        int encryptedKeyLength = encryptedKeyLengthByte[0] << 24 | (encryptedKeyLengthByte[1] & 0xFF) << 16 | (encryptedKeyLengthByte[2] & 0xFF) << 8 | (encryptedKeyLengthByte[3] & 0xFF);
        if(Crypto.getAlgo(algo)=="AES"){
            int headerLength = 4 + 4 + encryptedKeyLength + 16;
            byte[] datanoheader = new byte[data.length-headerLength];
            int begin = headerLength;
            for(int i=0; i< data.length-headerLength; i++){
                datanoheader[i] = data[begin];
                begin++;
            }
            return datanoheader;
        }
        if(Crypto.getAlgo(algo)=="DES"){
            int headerLength = 4 + 4 + encryptedKeyLength + 8;
            byte[] datanoheader = new byte[data.length-headerLength];
            int begin = headerLength;
            for(int i=0; i< data.length-headerLength; i++){
                datanoheader[i] = data[begin];
                begin++;
            }
            return datanoheader;
        }
        return null;
    }
    public static HashMap<String, User> importDataBase(String filepath) {
        HashMap<String, User> mapInFile = new HashMap<String, User>();
        try{
            File toRead = new File(filepath);
            FileInputStream fis = new FileInputStream(toRead);
            ObjectInputStream ois = new ObjectInputStream(fis);

            mapInFile = (HashMap<String,User>)ois.readObject();

            ois.close();
            fis.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        }
        return mapInFile;
    }
    public static void exportDataBase(HashMap<String, User> map, String filepath){  
        try{
            File fileOne = new File(filepath);
            FileOutputStream fos = new FileOutputStream(fileOne);
            ObjectOutputStream oos=new ObjectOutputStream(fos);

            oos.writeObject(map);
            oos.flush();
            oos.close();
            fos.close();
        }catch(Exception e){}
    }
    public static void exportUser(User user, String filepath){
        try{
            File fileOne = new File(filepath);
            FileOutputStream fos = new FileOutputStream(fileOne);
            ObjectOutputStream oos=new ObjectOutputStream(fos);

            oos.writeObject(user);
            oos.flush();
            oos.close();
            fos.close();
        }catch(Exception e){}
    }
    public static User importUser(String filepath){
       User user = null;
       try{
            File toRead = new File(filepath);
            FileInputStream fis = new FileInputStream(toRead);
            ObjectInputStream ois = new ObjectInputStream(fis);

            user = (User)ois.readObject();

            ois.close();
            fis.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
        }
       return user;
    }
}
